package com.google.code.securityflow.cfg

import com.google.code.securityflow.graphviz.GraphvizMultiNode

abstract sealed class BasicBlock(val id: Int) {
  def isEmpty: Boolean;

  def nodes: List[Node];

  def successors: Set[BasicBlock];

  def toGraphviz: GraphvizMultiNode;

  def toPrettyString: String;
}

class NormalBlock(id: Int, var nodes: List[Node], var successors: Set[BasicBlock]) extends BasicBlock(id) {
  def this(id: Int) = this (id, List.empty, Set.empty);

  def isEmpty = nodes.isEmpty;

  def addNode(node: Node) {
    nodes = nodes :+ node;
  }

  def addSuccessor(block: BasicBlock) {
    successors = successors + block;
  }

  def toGraphviz: GraphvizMultiNode = {
    GraphvizMultiNode(id, nodes.map(n => n.canonicalName), Set.empty);
  }

  override def toString = "NormalBlock@" + id;

  def toPrettyString = "NormalBlock[" + id + "]";
}

case class EntryBlock(override val id: Int, successor: BasicBlock) extends BasicBlock(id) {
  def isEmpty = true;

  def nodes = List.empty;

  def successors = Set(successor);

  def toGraphviz: GraphvizMultiNode = {
    GraphvizMultiNode(id, List("EntryBlock[" + id + "]"), Set.empty);
  }

  override def toString = "EntryBlock@" + id;

  def toPrettyString = "EntryBlock[" + id + "]";
}

case class ExitBlock(override val id: Int) extends BasicBlock(id) {
  def isEmpty = true;

  def nodes = List.empty;

  def successors = Set.empty;

  def toGraphviz: GraphvizMultiNode = {
    GraphvizMultiNode(id, List("ExitBlock[" + id + "]"), Set.empty);
  }

  override def toString = "ExitBlock@" + id;

  def toPrettyString = "ExitBlock[" + id + "]";
}

case class CallBlock(override val id: Int, node: CallNode, successor: BasicBlock) extends BasicBlock(id) {
  def isEmpty = false;

  def nodes = List(node);

  def successors = Set(successor);

  def toGraphviz: GraphvizMultiNode = {
    GraphvizMultiNode(id, List(node.canonicalName), Set.empty);
  }

  override def toString = "CallBlock@" + id;

  def toPrettyString = "CallBlock[" + id + "]";
}